package xyz.xtt.user.service.impl;

import static xyz.xtt.user.utils.AssertUtils.isFalse;
import static xyz.xtt.user.utils.AssertUtils.isNull;
import static xyz.xtt.user.utils.AssertUtils.isTrue;

import java.math.BigDecimal;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import cn.hutool.core.util.IdUtil;
import cn.hutool.json.JSONUtil;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Positive;
import lombok.extern.slf4j.Slf4j;
import xyz.xtt.asset.client.response.AssetInfoResponse;
import xyz.xtt.pay.api.dto.PayAttach;
import xyz.xtt.pay.api.dto.SplitAccountItem;
import xyz.xtt.pay.api.enums.PayOrderBusinessTypeEnum;
import xyz.xtt.pay.api.enums.PayOrderStatusEnum;
import xyz.xtt.pay.client.response.TblPayOrderDto;
import xyz.xtt.user.api.enums.UserFundRecordChangeStatus;
import xyz.xtt.user.api.enums.UserFundRecordChangeType;
import xyz.xtt.user.api.enums.UserFundRecordType;
import xyz.xtt.user.api.enums.UserFundRecordUserType;
import xyz.xtt.user.constants.ErrorMessage;
import xyz.xtt.user.entity.TblUserFundAccount;
import xyz.xtt.user.entity.TblUserFundRecord;
import xyz.xtt.user.exception.ChainException;
import xyz.xtt.user.mapper.TblUserFundAccountMapper;
import xyz.xtt.user.service.IInnerService;
import xyz.xtt.user.service.ITblUserFundAccountService;
import xyz.xtt.user.service.ITblUserFundRecordService;
import xyz.xtt.user.utils.RedisLockUtil;

/**
 * <p>
 * 用户资金账户余额表 服务实现类
 * </p>
 *
 * @author dale
 * @since 2025-02-25
 */
@Service
@RefreshScope
@Slf4j
public class TblUserFundAccountServiceImpl extends ServiceImpl<TblUserFundAccountMapper, TblUserFundAccount> implements ITblUserFundAccountService {
	@Autowired
	private ITblUserFundRecordService iTblUserFundRecordService;
	@Value("${settleIntervalDays:8}")
	private int settleIntervalDays;
	@Autowired
	private RedisLockUtil redisLockUtil;
	@Autowired
	private IInnerService iInnerService;

	/**
	 * c2c订单支付成功后记账
	 *
	 * @param payOrderDto
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public Boolean handleOrderPaySuccess(@NotNull TblPayOrderDto payOrderDto) {
		isFalse(Objects.equals(payOrderDto.getBusinessType(), PayOrderBusinessTypeEnum.C_TO_C.getCode()), ErrorMessage.ARGUMENT_NOT_VALID);
		isFalse(Objects.equals(payOrderDto.getPayStatus(), PayOrderStatusEnum.PAY_SUCCESS.getCode()), ErrorMessage.ARGUMENT_NOT_VALID);
		long buyerId = payOrderDto.getAppUserId();

		String lockKey = String.format(RedisLockUtil.LOCK_KEY_PAY_ORDER_UPDATE_ACCOUNT, payOrderDto.getPayOrderId());
		String lockValue = UUID.randomUUID().toString();
		boolean lock = false;
		try {
			lock = redisLockUtil.acquireLock(lockKey, lockValue, 1, TimeUnit.MINUTES);
			if (lock) {
				// 检查当前订单是否已处理
				if (hashAlreadyUpdateAccount4Order(payOrderDto.getPayOrderId())) {
					log.warn("handleOrderPaySuccess already update account4Order payOrderId: " + payOrderDto.getPayOrderId());
					return Boolean.FALSE;
				}

				PayAttach payAttach = JSONUtil.toBean(payOrderDto.getBusinessAttach(), PayAttach.class);
				long sellerId;
				if (payOrderDto.getSellerId() != null && payOrderDto.getSellerId() > 0) {
					sellerId = payOrderDto.getSellerId();
				} else {
					AssetInfoResponse tblAsset = iInnerService.infoWithGoodsId(payAttach.getGoodsId());
					sellerId = Long.valueOf(tblAsset.getOwnerId());
				}
				List<SplitAccountItem> splitAccountItems = payAttach.getSplitAccountDetails();
				SplitAccountItem sellerSplit = splitAccountItems
						.stream()
						.filter(item -> Objects.equals(item.getReceiverUserId(), sellerId))
						.findFirst()
						.orElse(null);
				isNull(sellerSplit, ErrorMessage.ARGUMENT_NOT_VALID, () -> log.error("handleOrderPaySuccess sellerSplit is empty"));
				BigDecimal totalPaid = payOrderDto.getPayMoney();
				BigDecimal sellerEarned = new BigDecimal(sellerSplit.getAmount());
				BigDecimal platformEarned = totalPaid.subtract(sellerEarned);
				Boolean skipRealPay = iInnerService.skipRealPay();
				if (!skipRealPay) {
					isFalse(sellerEarned.compareTo(BigDecimal.ZERO) > 0
							&& platformEarned.compareTo(BigDecimal.ZERO) >= 0, ErrorMessage.INVALID_SPLIT_ACCOUNT_DATA);
				}
				LocalDateTime now = LocalDateTime.now();

				isFalse(saveOrUpdateAccount4Order(sellerId, UserFundRecordChangeType.SELLER_INCOME, sellerEarned, now), ErrorMessage.UPDATE_USER_FUND_ACCOUNT_FAILED, () -> log
						.error("saveOrUpdateAccount4Order update seller failed payOrderId: " + payOrderDto.getPayOrderId()));
				isFalse(saveOrUpdateAccount4Order(0L, UserFundRecordChangeType.PLATFORM_INCOME, platformEarned, now), ErrorMessage.UPDATE_USER_FUND_ACCOUNT_FAILED, () -> log
						.error("saveOrUpdateAccount4Order update platform failed payOrderId: " + payOrderDto.getPayOrderId()));

				List<TblUserFundRecord> records = generateUserFundOrderPaySuccessRecords(payOrderDto
						.getPayOrderId(), buyerId, sellerId, totalPaid, sellerEarned, platformEarned, now, payOrderDto.getPaySuccessTime());
				isFalse(iTblUserFundRecordService.saveBatch(records), ErrorMessage.UPDATE_USER_FUND_ACCOUNT_FAILED, () -> log
						.error("saveOrUpdateAccount4Order update records failed payOrderId: " + payOrderDto.getPayOrderId()));
				return Boolean.TRUE;
			} else {
				log.error("handleOrderPaySuccess failed. lock failed. payOrderId:{}", payOrderDto.getPayOrderId());
				throw new ChainException(ErrorMessage.UNKNOWN_ERROR);
			}
		} finally {
			if (lock) {
				redisLockUtil.releaseLock(lockKey, lockValue);
			}
		}
	}

	private boolean hashAlreadyUpdateAccount4Order(Long payOrderId) {
		LambdaQueryChainWrapper<TblUserFundRecord> query = new LambdaQueryChainWrapper<>(iTblUserFundRecordService.getBaseMapper());
		return query.eq(TblUserFundRecord::getPayOrderId, payOrderId).count() > 0;
	}

	private boolean saveOrUpdateAccount4Order(long userId, UserFundRecordChangeType userFundRecordChangeType, BigDecimal amount, LocalDateTime now) {
		isFalse(Objects.equals(userFundRecordChangeType, UserFundRecordChangeType.PLATFORM_INCOME)
				|| Objects.equals(userFundRecordChangeType, UserFundRecordChangeType.SELLER_INCOME), ErrorMessage.ARGUMENT_NOT_VALID);

		TblUserFundAccount userFundAccount = getByUserId(userId);
		if (Objects.isNull(userFundAccount)) {
			userFundAccount = TblUserFundAccount
					.builder()
					.id(IdUtil.getSnowflakeNextId())
					.userId(userId)
					.balance(Objects.equals(userFundRecordChangeType, UserFundRecordChangeType.PLATFORM_INCOME) ? amount : BigDecimal.ZERO)
					.unsettledBalance(Objects.equals(userFundRecordChangeType, UserFundRecordChangeType.SELLER_INCOME) ? amount : BigDecimal.ZERO)
					.totalIncome(Objects.equals(userFundRecordChangeType, UserFundRecordChangeType.PLATFORM_INCOME) ? amount : BigDecimal.ZERO)
					.totalWithdraw(BigDecimal.ZERO)
					.ver(0L)
					.createTime(now)
					.updateTime(now)
					.build();
			return save(userFundAccount);
		}

		LambdaUpdateChainWrapper<TblUserFundAccount> update = new LambdaUpdateChainWrapper<>(baseMapper);
		update.eq(TblUserFundAccount::getUserId, userId);
		update.eq(TblUserFundAccount::getVer, userFundAccount.getVer());
		if (Objects.equals(userFundRecordChangeType, UserFundRecordChangeType.PLATFORM_INCOME)) {
			update.set(TblUserFundAccount::getTotalIncome, userFundAccount.getTotalIncome().add(amount));
			update.set(TblUserFundAccount::getBalance, userFundAccount.getBalance().add(amount));
		} else {
			update.set(TblUserFundAccount::getUnsettledBalance, userFundAccount.getUnsettledBalance().add(amount));
		}
		return update.set(TblUserFundAccount::getUpdateTime, now).set(TblUserFundAccount::getVer, userFundAccount.getVer() + 1).update();
	}

	private TblUserFundAccount getByUserId(long userId) {
		LambdaQueryChainWrapper<TblUserFundAccount> query = new LambdaQueryChainWrapper<>(baseMapper);
		return query.eq(TblUserFundAccount::getUserId, userId).one();
	}

	private List<TblUserFundRecord> generateUserFundOrderPaySuccessRecords(long payOrderId, long buyerId, long sellerId, BigDecimal totalPaid,
			BigDecimal sellerEarned, BigDecimal platformEarned, LocalDateTime now, Long paySuccessTime) {
		return List
				.of(TblUserFundRecord
						.builder()
						.id(IdUtil.getSnowflakeNextId())
						.recordType(UserFundRecordType.ORDER.getCode())
						.payOrderId(payOrderId)
						.userType(UserFundRecordUserType.SELLER.getCode())
						.userId(sellerId)
						.changeType(UserFundRecordChangeType.SELLER_INCOME.getCode())
						.amount(sellerEarned)
						.changeStatus(UserFundRecordChangeStatus.UN_SETTLE.getCode())
						.settlePlanTime(calculateSettlePlanTime(paySuccessTime))
						.createTime(now)
						.updateTime(now)
						.ver(0L)
						.build(), TblUserFundRecord
								.builder()
								.id(IdUtil.getSnowflakeNextId())
								.recordType(UserFundRecordType.ORDER.getCode())
								.payOrderId(payOrderId)
								.userType(UserFundRecordUserType.BUYER.getCode())
								.userId(buyerId)
								.changeType(UserFundRecordChangeType.BUYER_PAID.getCode())
								.amount(totalPaid)
								.changeStatus(UserFundRecordChangeStatus.PAID.getCode())
								.createTime(now)
								.updateTime(now)
								.ver(0L)
								.build(), TblUserFundRecord
										.builder()
										.id(IdUtil.getSnowflakeNextId())
										.recordType(UserFundRecordType.ORDER.getCode())
										.payOrderId(payOrderId)
										.userType(UserFundRecordUserType.PLATFORM.getCode())
										.userId(0L)
										.changeType(UserFundRecordChangeType.PLATFORM_INCOME.getCode())
										.amount(platformEarned)
										.changeStatus(UserFundRecordChangeStatus.SETTLE_COMPLETE.getCode())
										.createTime(now)
										.updateTime(now)
										.ver(0L)
										.build());
	}

	/**
	 * 计算结算计划时间
	 *
	 * @param paySuccessTime
	 * @return
	 */
	private LocalDateTime calculateSettlePlanTime(Long paySuccessTime) {
		LocalDateTime paySuccessLocalDateTime = Instant.ofEpochMilli(paySuccessTime).atZone(ZoneId.systemDefault()).toLocalDateTime();
		return paySuccessLocalDateTime.plusDays(settleIntervalDays);
	}

	/**
	 * c2c订单取消后修改记账
	 *
	 * @param payOrderDto
	 */
	@Override
	public void handleOrderRefundSuccess(@NotNull TblPayOrderDto payOrderDto) {
		isFalse(Objects.equals(payOrderDto.getBusinessType(), PayOrderBusinessTypeEnum.C_TO_C.getCode()), ErrorMessage.ARGUMENT_NOT_VALID);
		isFalse(Objects.equals(payOrderDto.getPayStatus(), PayOrderStatusEnum.REFUND_SUCCESS.getCode()), ErrorMessage.ARGUMENT_NOT_VALID);

		String lockKey = String.format(RedisLockUtil.LOCK_KEY_PAY_ORDER_UPDATE_ACCOUNT, payOrderDto.getPayOrderId());
		String lockValue = UUID.randomUUID().toString();
		boolean lock = false;
		try {
			lock = redisLockUtil.acquireLock(lockKey, lockValue, 1, TimeUnit.MINUTES);
			if (lock) {
				List<TblUserFundRecord> records = queryOrderRecords(payOrderDto.getPayOrderId());
				isTrue(CollectionUtils
						.isEmpty(records), ErrorMessage.UPDATE_USER_FUND_ACCOUNT_FAILED, () -> log.error("handleOrderRefundSuccess failed records is empty"));
				for (TblUserFundRecord record : records) {
					if (Objects.equals(record.getUserType(), UserFundRecordUserType.BUYER.getCode())) {
						isFalse(new LambdaUpdateChainWrapper<>(iTblUserFundRecordService.getBaseMapper())
								.eq(TblUserFundRecord::getId, record.getId())
								.eq(TblUserFundRecord::getVer, record.getVer())
								.eq(TblUserFundRecord::getChangeStatus, UserFundRecordChangeStatus.PAID.getCode())
								.set(TblUserFundRecord::getChangeStatus, UserFundRecordChangeStatus.REFUND_COMPLETE.getCode())
								.set(TblUserFundRecord::getUpdateTime, LocalDateTime.now())
								.set(TblUserFundRecord::getVer, record.getVer() + 1)
								.update(), ErrorMessage.UPDATE_USER_FUND_ACCOUNT_FAILED, () -> log
										.error("handleOrderRefundSuccess failed. update buyer record failed."));
					} else if (Objects.equals(record.getUserType(), UserFundRecordUserType.SELLER.getCode())) {
						isFalse(new LambdaUpdateChainWrapper<>(iTblUserFundRecordService.getBaseMapper())
								.eq(TblUserFundRecord::getId, record.getId())
								.eq(TblUserFundRecord::getVer, record.getVer())
								.eq(TblUserFundRecord::getChangeStatus, UserFundRecordChangeStatus.UN_SETTLE.getCode())
								.set(TblUserFundRecord::getChangeStatus, UserFundRecordChangeStatus.REFUND_COMPLETE.getCode())
								.set(TblUserFundRecord::getUpdateTime, LocalDateTime.now())
								.set(TblUserFundRecord::getVer, record.getVer() + 1)
								.update(), ErrorMessage.UPDATE_USER_FUND_ACCOUNT_FAILED, () -> log
										.error("handleOrderRefundSuccess failed. update seller record failed."));

						TblUserFundAccount sellerAccount = getByUserId(record.getUserId());
						isFalse(new LambdaUpdateChainWrapper<>(this.getBaseMapper())
								.eq(TblUserFundAccount::getId, sellerAccount.getId())
								.eq(TblUserFundAccount::getVer, sellerAccount.getVer())
								.gt(TblUserFundAccount::getUnsettledBalance, record.getAmount())
								.set(TblUserFundAccount::getUnsettledBalance, sellerAccount.getUnsettledBalance().subtract(record.getAmount()))
								.set(TblUserFundAccount::getUpdateTime, LocalDateTime.now())
								.set(TblUserFundAccount::getVer, sellerAccount.getVer() + 1)
								.update(), ErrorMessage.UPDATE_USER_FUND_ACCOUNT_FAILED, () -> log
										.error("handleOrderRefundSuccess failed. update seller account failed."));
					} else if (Objects.equals(record.getUserType(), UserFundRecordUserType.PLATFORM.getCode())) {
						isFalse(new LambdaUpdateChainWrapper<>(iTblUserFundRecordService.getBaseMapper())
								.eq(TblUserFundRecord::getId, record.getId())
								.eq(TblUserFundRecord::getVer, record.getVer())
								.set(TblUserFundRecord::getChangeStatus, UserFundRecordChangeStatus.REFUND_COMPLETE.getCode())
								.set(TblUserFundRecord::getUpdateTime, LocalDateTime.now())
								.set(TblUserFundRecord::getVer, record.getVer() + 1)
								.update(), ErrorMessage.UPDATE_USER_FUND_ACCOUNT_FAILED, () -> log
										.error("handleOrderRefundSuccess failed. update platform record failed."));

						TblUserFundAccount platformAccount = getByUserId(record.getUserId());
						isFalse(new LambdaUpdateChainWrapper<>(this.getBaseMapper())
								.eq(TblUserFundAccount::getId, platformAccount.getId())
								.eq(TblUserFundAccount::getVer, platformAccount.getVer())
								.gt(TblUserFundAccount::getBalance, record.getAmount())
								.set(TblUserFundAccount::getBalance, platformAccount.getBalance().subtract(record.getAmount()))
								.set(TblUserFundAccount::getUpdateTime, LocalDateTime.now())
								.set(TblUserFundAccount::getVer, platformAccount.getVer() + 1)
								.update(), ErrorMessage.UPDATE_USER_FUND_ACCOUNT_FAILED, () -> log
										.error("handleOrderRefundSuccess failed. update platform account failed."));
					}
				}
			} else {
				log.error("handleOrderRefundSuccess failed. can not get lock. payOrder:{}", JSONUtil.toJsonStr(payOrderDto));
			}
		} finally {
			if (lock) {
				redisLockUtil.releaseLock(lockKey, lockValue);
			}
		}
		throw new ChainException(ErrorMessage.UNKNOWN_ERROR);
	}

	/**
	 * 获取需要结算的记录
	 *
	 * @param maxCount
	 * @return
	 */
	@Override
	public List<TblUserFundRecord> getNeedSettleRecords(int maxCount, Long lastId) {
		isFalse(maxCount > 0 && maxCount <= 20, ErrorMessage.ARGUMENT_NOT_VALID, () -> log
				.error("getNeedSettleRecords failed. maxCount must be greater than 0 and less than 20."));
		LambdaQueryChainWrapper<TblUserFundRecord> query = new LambdaQueryChainWrapper<>(iTblUserFundRecordService.getBaseMapper());
		if (lastId != null && lastId > 0) {
			query.gt(TblUserFundRecord::getId, lastId);
		}
		return query
				.le(TblUserFundRecord::getSettlePlanTime, LocalDateTime.now())
				.eq(TblUserFundRecord::getChangeStatus, UserFundRecordChangeStatus.UN_SETTLE.getCode())
				.eq(TblUserFundRecord::getUserType, UserFundRecordUserType.SELLER.getCode())
				.last("limit " + maxCount)
				.list();
	}

	/**
	 * 获取需要结算的记录
	 *
	 * @param sellerUserId
	 * @param maxCount
	 * @return
	 */
	@Override
	public List<TblUserFundRecord> getNeedSettleRecords(long sellerUserId, int maxCount, Long lastId) {
		isFalse(sellerUserId > 0, ErrorMessage.ARGUMENT_NOT_VALID, () -> log.error("getNeedSettleRecords failed. sellerUserId must be greater than 0."));
		isFalse(maxCount > 0 && maxCount <= 20, ErrorMessage.ARGUMENT_NOT_VALID, () -> log
				.error("getNeedSettleRecords failed. maxCount must be greater than 0 and less than 20."));
		LambdaQueryChainWrapper<TblUserFundRecord> query = new LambdaQueryChainWrapper<>(iTblUserFundRecordService.getBaseMapper());
		if (lastId != null && lastId > 0) {
			query.gt(TblUserFundRecord::getId, lastId);
		}
		return query
				.le(TblUserFundRecord::getSettlePlanTime, LocalDateTime.now())
				.eq(TblUserFundRecord::getChangeStatus, UserFundRecordChangeStatus.UN_SETTLE.getCode())
				.eq(TblUserFundRecord::getUserType, UserFundRecordUserType.SELLER.getCode())
				.eq(TblUserFundRecord::getUserId, sellerUserId)
				.last("limit " + maxCount)
				.list();
	}

	/**
	 * 执行资金结算
	 *
	 * @param userFundRecordId
	 * @return
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean updateFundSettled(@Positive long userFundRecordId) {
		TblUserFundRecord record = iTblUserFundRecordService.getById(userFundRecordId);
		isNull(record, ErrorMessage.USER_FUND_RECORD_NOT_EXIST);
		isFalse(Objects.equals(record.getChangeStatus(), UserFundRecordChangeStatus.UN_SETTLE.getCode())
				&& Objects.equals(record.getUserType(), UserFundRecordUserType.SELLER.getCode())
				&& record.getSettlePlanTime().isAfter(LocalDateTime.now()), ErrorMessage.SELLER_FUND_CAN_NOT_BE_SETTLED);

		TblUserFundAccount sellerAccount = getByUserId(record.getUserId());
		isNull(sellerAccount, ErrorMessage.USER_FUND_ACCOUNT_NOT_EXIST);
		isFalse(sellerAccount.getUnsettledBalance().compareTo(record.getAmount()) >= 0, ErrorMessage.USER_FUND_ACCOUNT_DATA_ERROR, () -> log
				.error("updateFundSettled failed. seller account unsettled balance is not enough. sellerAccount:{} fundRecord:{}", sellerAccount, record));
		LambdaUpdateChainWrapper<TblUserFundAccount> update = new LambdaUpdateChainWrapper<>(this.getBaseMapper());
		isFalse(update
				.eq(TblUserFundAccount::getId, sellerAccount.getId())
				.eq(TblUserFundAccount::getVer, sellerAccount.getVer())
				.ge(TblUserFundAccount::getUnsettledBalance, record.getAmount())
				.set(TblUserFundAccount::getUnsettledBalance, sellerAccount.getUnsettledBalance().subtract(record.getAmount()))
				.set(TblUserFundAccount::getBalance, sellerAccount.getBalance().add(record.getAmount()))
				.set(TblUserFundAccount::getUpdateTime, LocalDateTime.now())
				.set(TblUserFundAccount::getVer, sellerAccount.getVer() + 1)
				.update(), ErrorMessage.UPDATE_USER_FUND_ACCOUNT_FAILED, () -> log
						.error("updateFundSettled failed. update seller account failed. sellerAccount:{} fundRecord:{}", sellerAccount, record));

		LambdaUpdateChainWrapper<TblUserFundRecord> updateRecord = new LambdaUpdateChainWrapper<>(iTblUserFundRecordService.getBaseMapper());
		isFalse(updateRecord
				.eq(TblUserFundRecord::getId, record.getId())
				.eq(TblUserFundRecord::getVer, record.getVer())
				.eq(TblUserFundRecord::getChangeStatus, UserFundRecordChangeStatus.UN_SETTLE.getCode())
				.set(TblUserFundRecord::getChangeStatus, UserFundRecordChangeStatus.SETTLE_COMPLETE.getCode())
				.set(TblUserFundRecord::getSettleCompleteTime, LocalDateTime.now())
				.set(TblUserFundRecord::getUpdateTime, LocalDateTime.now())
				.set(TblUserFundRecord::getVer, record.getVer() + 1)
				.update(), ErrorMessage.UPDATE_USER_FUND_ACCOUNT_FAILED, () -> log
						.error("updateFundSettled failed. update seller fund record failed. sellerAccount:{} fundRecord:{}", sellerAccount, record));

		return true;
	}

	/**
	 * 执行资金结算
	 *
	 * @param sellerUserId
	 * @return
	 */
	@Override
	public boolean updateSellerFundSettled(long sellerUserId) {
		Long lastId = null;
		int querySize = 20;
		while (true) {
			List<TblUserFundRecord> records = getNeedSettleRecords(sellerUserId, querySize, lastId);
			if (records.isEmpty()) {
				break;
			}
			for (TblUserFundRecord record : records) {
				try {
					updateFundSettled(record.getId());
				} catch (Exception e) {
					log.error("updateSellerFundSettled failed. sellerUserId:{} record:{}", sellerUserId, record, e);
				}
			}
			lastId = records.get(records.size() - 1).getId();
		}
		return true;
	}

	private List<TblUserFundRecord> queryOrderRecords(Long payOrderId) {
		LambdaQueryChainWrapper<TblUserFundRecord> query = new LambdaQueryChainWrapper<>(iTblUserFundRecordService.getBaseMapper());
		return query.eq(TblUserFundRecord::getPayOrderId, payOrderId).list();
	}
}
